home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Games of Daze
/
Infomagic - Games of Daze (Summer 1995) (Disc 1 of 2).iso
/
djgpp
/
go32
/
fs
/
serial.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-03-23
|
17KB
|
639 lines
#include <stdio.h>
#include <std.h>
#include <sys/types.h>
#include <dos.h>
#include <pc.h>
#include <go32.h>
#include <dpmi.h>
#define far
#include "ed.h"
#include "unassmbl.h"
#include "serial.h"
#include "syms.h"
#define MaxPort 4
static int UartBase[MaxPort] = { 0x3F8, 0x2F8, 0x3E8, 0x2E8 };
static int IntNums [MaxPort] = { 0x0C, 0x0B, 0x0C, 0x0B };
static int I8259Levels[MaxPort] = {4, 3, 4, 3};
static int ComInstalled = 0;
static unsigned int UartData; /*Data register*/
static unsigned int UartIer ; /*Interrupt enable register*/
static unsigned int UartIir ; /*Interrupt identification register*/
static unsigned int UartLcr ; /*Line control register*/
static unsigned int UartMcr ; /*Modem control register*/
static unsigned int UartLsr ; /*Line status register*/
static unsigned int UartMsr ; /*Modem status register*/
static unsigned int UartSpr ; /*Scratch pad register */
static unsigned char OldIer, OldMcr;
static unsigned int OldI8259Mask;
static _go32_dpmi_seginfo rm_old_irq;
static _go32_dpmi_registers rm_regs;
static _go32_dpmi_seginfo rm_si;
static _go32_dpmi_seginfo pm_old_irq;
static _go32_dpmi_seginfo pm_si;
static _go32_dpmi_seginfo rm_old_irq_1c;
static _go32_dpmi_registers rm_regs_1c;
static _go32_dpmi_seginfo rm_si_1c;
static unsigned int I8259Bit;
static unsigned int IntNum;
typedef char *comnames;
static comnames DOSDEV[5] = { "CON", "COM1", "COM2", "COM3", "COM4" };
volatile unsigned long eip, ebp, esp, eflag;
#define RxQueueSize 4096
#define TxQueueSize 4096
static char RxQueue[RxQueueSize];
static char TxQueue[TxQueueSize];
static unsigned int RxIn, RxOut, TxIn, TxOut; /*Index of next character*/
static unsigned int RxChars, TxChars; /*Number of chars in queue*/
static int curr_port = 0;
static int int_1c_counts = 0;
static word32 caller_address = 0;
static word32 caller_value = 0;
extern int is_in_running_mode;
/* ---------------------------------------------------------------------- */
static char *stack;
static word32 my_esp, my_ebp, my_ss, old_esp, old_ebp, old_ss;
static switch_stack = 0;
/* ---------------------------------------------------------------------- */
static void
refresh_uart (void)
{ /* outportb (UartIer, 0); */
asm ("xor %al, %al \n\
mov _UartIer, %dx \n\
out %al, %dx");
/* outportb (0x21, OldI8259Mask | I8259Bit); */
asm ("mov $0x21, %dx \n\
mov _OldI8259Mask, %al \n\
or _I8259Bit, %al \n\
out %al, %dx");
/* outportb (UartLcr, 3); */
asm ("mov $0x03, %al \n\
mov _UartLcr, %dx \n\
out %al, %dx");
/* outportb (UartMcr, 0x0a | (OldMcr & 1)); */
asm ("mov _UartMcr, %dx \n\
mov _OldMcr, %al \n\
and $0x01, %al \n\
or $0x0a, %al \n\
out %al, %dx");
/* outportb (UartIer, inportb (UartIer) | 1);*/
asm ("mov _UartIer, %dx \n\
in %dx, %al \n\
or $0x01, %al \n\
out %al, %dx");
/*outportb (0x21, inportb (0x21) & ~I8259Bit);*/
asm ("mov $0x21, %dx \n\
mov _I8259Bit, %cl \n\
not %cl \n\
in %dx, %al \n\
and %cl, %al \n\
out %al, %dx");
TxChars = 0;
TxIn = 0;
TxOut = 0;
}
/* ---------------------------------------------------------------------- */
static void
rm_isr_1c (void)
{ if (is_in_running_mode)
{ if (++int_1c_counts >= 18)
{ refresh_uart ();
int_1c_counts = 0;
}
}
}
/* ---------------------------------------------------------------------- */
static int ch, Iir, ctrl_c_hit;
/* ---------------------------------------------------------------------- */
static void
ComInterruptDriver (void)
{
asm("cli");
/* if (switch_stack)
asm("movl %esp, %eax \n\
movl %eax, _old_esp \n\
movl %ebp, %eax \n\
movl %eax, _old_ebp \n\
movw %ss, %ax \n\
movw %ax, _old_ss \n\
movl _my_esp, %eax \n\
movl %eax, %esp \n\
movl _my_ebp, %eax \n\
movl %eax, %ebp \n\
movw _my_ss, %ax \n\
movw %ax, %ss \n\
"); */
Iir = inportb (UartIir);
while (!(Iir % 2))
{
ch = 0;
switch (Iir >> 1)
{
case 2:
ch = inportb (UartData); /* realmode: cannot get accurate eip. */
if (ch == 3)
ctrl_c_hit = 1;
if (RxChars < RxQueueSize)
{
RxQueue [RxIn] = ch;
RxIn++;
if (RxIn >= RxQueueSize)
RxIn = 0;
RxChars++;
}
break;
case 1:
if (TxChars <= 0)
outportb (UartIer, inportb (UartIer) & ~2);
else if ((inportb (UartLsr) >> 5) %2)
{
outportb (UartData, TxQueue [TxOut]);
TxOut++;
if (TxOut >= TxQueueSize)
TxOut = 0;
TxChars--;
}
break;
case 0:
(void) inportb (UartMsr);
break;
case 3:
ch = inportb (UartLsr);
break;
}
Iir = inportb (UartIir);
}
outportb (0x20, 0x20);
/* if (switch_stack)
asm("movl %esp, %eax \n\
movl %eax, _my_esp \n\
movl %ebp, %eax \n\
movl %eax, _my_ebp \n\
movl _old_esp, %eax \n\
movl %eax, %esp \n\
movl _old_ebp, %eax \n\
movl %eax, %ebp \n\
movw _old_ss, %ax \n\
movw %ax, %ss \n\
leave \n\
ret \n\
"); */
}
/* ---------------------------------------------------------------------- */
static void
pmComInterruptDriver (_go32_dpmi_registers r)
{
asm("cli \n\
push %eax \n\
push %ebx \n\
push %ecx \n\
push %edx \n\
push %esi \n\
push %edi \n\
");
asm("push %ds \n\
movw $0x107, %ax \n\
movw %ax, %ds \n\
");
/* if (switch_stack)
asm("movl %esp, %eax \n\
movl %eax, _old_esp \n\
movl %ebp, %eax \n\
movl %eax, _old_ebp \n\
movw %ss, %ax \n\
movw %ax, _old_ss \n\
movl _my_esp, %eax \n\
movl %eax, %esp \n\
movl _my_ebp, %eax \n\
movl %eax, %ebp \n\
movw _my_ss, %ax \n\
movw %ax, %ss \n\
"); */
Iir = inportb (UartIir);
while (!(Iir % 2))
{
switch (Iir >> 1)
{
case 2:
ch = inportb (UartData);
if (ch == 3)
ctrl_c_hit = 1;
if (RxChars < RxQueueSize)
{
RxQueue [RxIn] = ch;
RxIn++;
if (RxIn >= RxQueueSize)
RxIn = 0;
RxChars++;
}
break;
case 1:
if (TxChars <= 0)
outportb (UartIer, inportb (UartIer) & ~2);
else if ((inportb (UartLsr) >> 5) %2)
{
outportb (UartData, TxQueue [TxOut]);
TxOut++;
if (TxOut >= TxQueueSize)
TxOut = 0;
TxChars--;
}
break;
case 0:
(void) inportb (UartMsr);
break;
case 3:
ch = inportb (UartLsr);
break;
}
Iir = inportb (UartIir);
}
if (ctrl_c_hit)
{ ctrl_c_hit = 0;
if (is_in_running_mode && !switch_stack)
{ asm("movl %ebp,%eax");
asm("add $0x0c,%eax");
asm("movl (%eax),%edx");
asm("movl %edx,_eflag");
eflag |= 0x0100;
asm("movl %ebp,%eax");
asm("add $0x0c,%eax");
asm("movl _eflag,%edx");
asm("movl %edx,(%eax)");
}
}
asm("mov $0x20,%al");
asm("out %al,$0x20");
/* if (switch_stack)
asm("movl %esp, %eax \n\
movl %eax, _my_esp \n\
movl %ebp, %eax \n\
movl %eax, _my_ebp \n\
movl _old_esp, %eax \n\
movl %eax, %esp \n\
movl _old_ebp, %eax \n\
movl %eax, %ebp \n\
movw _old_ss, %ax \n\
movw %ax, %ss \n\
"); */
asm("pop %ds");
asm("pop %edi \n\
pop %esi \n\
pop %edx \n\
pop %ecx \n\
pop %ebx \n\
pop %eax \n\
leave \n\
iret \n\
");
}
/* ---------------------------------------------------------------------- */
static void
com_install_refresh_int (void)
{ int ret;
word32 value;
value = (word32) refresh_uart;
caller_address = syms_name2val ("Dosx_call_debugger_every_sec");
if (undefined_symbol)
{ undefined_symbol = 0;
caller_address = 0;
}
if (caller_address)
{ read_child (caller_address, &caller_value, sizeof (word32));
write_child (caller_address, &value, sizeof (word32));
} else
{ rm_si_1c.pm_offset = (int) rm_isr_1c;
ret = _go32_dpmi_allocate_real_mode_callback_iret(&rm_si_1c, &rm_regs_1c);
disable();
_go32_dpmi_get_real_mode_interrupt_vector(0x1c, &rm_old_irq_1c);
_go32_dpmi_set_real_mode_interrupt_vector(0x1c, &rm_si_1c);
enable();
}
}
/* ---------------------------------------------------------------------- */
static void
com_remove_refresh_int (void)
{ if (caller_address)
{ write_child (caller_address, &caller_value, sizeof (word32));
} else
{ disable ();
_go32_dpmi_set_real_mode_interrupt_vector(0x1c, &rm_old_irq_1c);
_go32_dpmi_free_real_mode_callback(&rm_si_1c);
enable ();
}
}
/* ---------------------------------------------------------------------- */
static int
com_install_rm_irq (int vect_num)
{ int ret;
rm_si.pm_offset = (int) ComInterruptDriver;
ret = _go32_dpmi_allocate_real_mode_callback_iret(&rm_si, &rm_regs);
if (ret)
return 0;
disable();
_go32_dpmi_get_real_mode_interrupt_vector(vect_num, &rm_old_irq);
_go32_dpmi_set_real_mode_interrupt_vector(vect_num, &rm_si);
enable();
com_install_refresh_int ();
return 1;
}
/* ---------------------------------------------------------------------- */
static void
com_remove_rm_irq (int vect_num)
{ com_remove_refresh_int ();
disable();
_go32_dpmi_set_real_mode_interrupt_vector(vect_num, &rm_old_irq);
_go32_dpmi_free_real_mode_callback(&rm_si);
enable();
}
/* ---------------------------------------------------------------------- */
static void
com_install_pm_irq (int vect_num)
{ disable();
_go32_dpmi_get_protected_mode_interrupt_vector(vect_num, &pm_old_irq);
pm_si.pm_offset = (int) pmComInterruptDriver;
pm_si.pm_selector = _go32_my_cs();
_go32_dpmi_set_protected_mode_interrupt_vector(vect_num, &pm_si);
enable();
}
/* ---------------------------------------------------------------------- */
static void
com_remove_pm_irq (int vect_num)
{ disable();
_go32_dpmi_set_protected_mode_interrupt_vector(vect_num, &pm_old_irq);
enable();
}
/* ---------------------------------------------------------------------- */
static int
install_irq (int vect_num)
{ if (_go32_info_block.run_mode == _GO32_RUN_MODE_DPMI)
{ switch_stack = 1;
stack = (char *)1; /* malloc (0x4000); */
if (!stack)
return (0);
my_esp = (word32)stack + 0x4000 - 8;
my_ebp = my_esp;
old_esp = 0;
old_ebp = 0;
old_ss = 0;
}
my_ss = _go32_my_ds ();
write_child ((word32)pmComInterruptDriver + 0x0d, &my_ss, 2);
if (!com_install_rm_irq(vect_num))
return 0;
com_install_pm_irq(vect_num);
return 1;
}
/* ---------------------------------------------------------------------- */
static void
remove_irq (int vect_num)
{ com_remove_rm_irq(vect_num);
com_remove_pm_irq(vect_num);
}
/* ---------------------------------------------------------------------- */
void
com_flush_rx (void)
{ disable();
RxChars = 0;
RxIn = 0;
RxOut = 0;
enable();
}
/* ---------------------------------------------------------------------- */
void
com_flush_tx (void)
{ disable();
TxChars = 0;
TxIn = 0;
TxOut = 0;
enable();
}
/* ---------------------------------------------------------------------- */
int
com_carrier (void)
{ return ComInstalled && ((inportw (UartMsr) >> 7) %2);
}
/* ---------------------------------------------------------------------- */
int
com_tx_ready (void)
{ return (TxChars < TxQueueSize);
}
/* ---------------------------------------------------------------------- */
int
com_tx_empty (void)
{ return (TxChars == 0);
}
/* ---------------------------------------------------------------------- */
int
com_rx_empty (void)
{ return (RxChars == 0);
}
/* ---------------------------------------------------------------------- */
void
com_lower_dtr (void)
{ if (ComInstalled)
{ disable();
outportb (UartMcr, inportb (UartMcr) & ~1);
enable();
}
}
/* ---------------------------------------------------------------------- */
void
com_raise_dtr (void)
{ if (ComInstalled)
{ disable();
outportb (UartMcr, inportb (UartMcr) | 1);
enable();
}
}
/* ---------------------------------------------------------------------- */
void
com_set_speed (unsigned int Speed)
{ int Divisor;
if (ComInstalled)
{ if (Speed < 2)
Speed = 2;
Divisor = 115200L / Speed;
disable();
outportb (UartLcr, inportb (UartLcr) | 0x80);
outportw (UartData, Divisor);
outportb (UartLcr, inportb (UartLcr) & ~0x80);
enable();
}
}
/* ---------------------------------------------------------------------- */
void
com_set_parity (void)
{ int Lcr;
Lcr = 0x00 | 0x03;
disable();
outportb (UartLcr, (inportb (UartLcr) & 0x40) | Lcr);
enable();
}
/* ---------------------------------------------------------------------- */
int
com_install (int PortNum)
{ if (ComInstalled)
return 3;
if ((PortNum < 1) || (PortNum > MaxPort))
return 1;
UartData = UartBase [PortNum - 1];
UartIer = UartData + 1;
UartIir = UartData + 2;
UartLcr = UartData + 3;
UartMcr = UartData + 4;
UartLsr = UartData + 5;
UartMsr = UartData + 6;
UartSpr = UartData + 7;
IntNum = IntNums [PortNum - 1];
I8259Bit = 1 << I8259Levels [PortNum - 1];
OldIer = inportb (UartIer);
outportb (UartIer, 0);
if (inportb (UartIer) != 0)
return 2;
disable();
OldI8259Mask = inportb (0x21);
outportb (0x21, OldI8259Mask | I8259Bit);
enable();
com_flush_tx();
com_flush_rx();
if (!install_irq (IntNum))
return 4;
ComInstalled = 1;
outportb (UartLcr, 3);
disable();
OldMcr = inportb (UartMcr);
outportb (UartMcr, 0x0a | (OldMcr & 1));
enable();
outportb (UartIer, 1);
disable();
outportb (0x21, inportb (0x21) & ~I8259Bit);
enable();
curr_port = PortNum;
return 0;
}
/* ---------------------------------------------------------------------- */
static void
redirect_init (int dev_num)
{ freopen (DOSDEV[dev_num], "w", stderr);
freopen (DOSDEV[dev_num], "r", stdin);
freopen (DOSDEV[dev_num], "w", stdout);
}
/* ---------------------------------------------------------------------- */
static void
redirect_done (void)
{ redirect_init (0);
}
/* ---------------------------------------------------------------------- */
int
com_init (int port_num)
{ int i;
i = com_install (port_num);
if (i)
return i;
com_set_speed (9600);
com_set_parity();
redirect_init (port_num);
ComInstalled = 1;
return 0;
}
/* ---------------------------------------------------------------------- */
void
com_done (void)
{ if (ComInstalled)
{ ComInstalled = 0;
outportb (UartMcr, OldMcr);
outportb (UartIer, OldIer);
disable();
outportb (0x21, ((inportb (0x21) & ~I8259Bit) | OldI8259Mask) & I8259Bit);
enable();
remove_irq (IntNum);
redirect_done ();
}
}
/* ---------------------------------------------------------------------- */
int
com_rx (void)
{ int temp = 0;
if (!RxChars)
return 0;
if (!ComInstalled)
return 0;
asm("cli");
temp = RxQueue[RxOut];
RxOut++;
if (RxOut >= RxQueueSize)
RxOut = 0;
RxChars--;
asm("sti");
return temp;
}
/* ---------------------------------------------------------------------- */
void
com_tx (int ch)
{ if (ComInstalled)
{ do {
} while (!com_tx_ready);
asm("cli");
TxQueue [TxIn] = ch;
TxIn++;
if (TxIn >= TxQueueSize)
TxIn = 0;
TxChars++;
outportb (UartIer, inportb (UartIer) | 2);
asm("sti");
}
}
/* ---------------------------------------------------------------------- */
void
com_txs (char *s)
{ if (ComInstalled)
{ while (*s)
{ do {
} while (TxChars >= TxQueueSize);
asm("cli");
do {
TxQueue [TxIn] = *s++;
TxIn++;
if (TxIn >= TxQueueSize)
TxIn = 0;
TxChars++;
} while ((TxChars < TxQueueSize) && (*s));
outportb (UartIer, inportb (UartIer) | 2);
asm("sti");
}
}
}
/* ---------------------------------------------------------------------- */